【クリスマスだし】UISwtich/UISegmentedControlライクなカスタムコントロール「SVSegmentedControl」【25日目の2】
ラベルやデザインの変更が容易でないことや、イベント発生条件がシビアなことで有名なUISwitchとUISegmentedControlですが、これらのコンポーネントをより使いやすくした感じのカスタムコントロールSVSegmentedControlをご紹介します!
おさらい
UISwitch
UISwitchは設定画面などで良く目にするコントロールの1つですが、超簡単に言うとタップしやすいチェックボタンです。表示されるラベルはオン/オフの2種類で、端末やアプリの言語設定に応じて言語が変わります。ちなみに、端末とアプリで言語設定が異なるとI/O表記になるそうです。
ラベル変更がむずい
表示されるラベルを変更するのが容易ではありません。面倒くさいです。よく紹介されているのは、UISwitchのサブビューに直接アクセスして変更する方法やサブクラスを作成して変更する方法などがありますが、公式のやり方ではないためiOSのバージョンが上がると使えなくなる可能性があります。きっとこのコントロールはオン/オフの切り替えのみに使うべきなんでしょう。
UISegmentedControl
UISegmentedControlは画面表示の切り替えなどで良く目にしますね。これも超簡単に言うとタップしやすいラジオボタンです。
生成後のラベル変更がむずい
UISwitchと違って、ラベルはインスタンス生成時に文字列の配列で指定します。が、いったん生成すると、あとから変更することが困難です。これもサブビューにアクセスするなどして解決することができますが、UISwitchと同様iOSのバージョンが上がると使えなくなる可能性があります。
UISwitch/UISegmentedControlの両方で使いにくいところ
デザインの変更が難しい
上記のようにラベルの変更だけでもくせがあるのですが、デザインを変更するとなるとより大変です。
ハンドリングできるイベントが少ない
両方とも主にUIControlEventValueChangedイベントをハンドリングできるようになっています。このイベントは値が変わったときに呼ばれるイベントなので、値が変わらなければ呼ばれません。言い換えれば、選択中の値をもう一度選択しても呼ばれません。 かといってタッチ系のイベントをハンドリングするにはサブクラスを作らなければなりません。
そこでSVSegmentedControl!!
というわけで、本題のSVSegmentedControlの登場です。これを使うと上で記したような煩わしい部分を一挙に解決してくれます!!
早速使ってみよう!!
ここからは以下の環境で説明します。
Mac OS X 10.8 Moutain lion
Xcode 4.5.2
iOS SDK 6.0
まずはダウンロード
早速ダウンロードしましょう。SVSegmentedControlはGitHubで公開されています。
samvermette/SVSegmentedControl
サンプルプロジェクトを作成
まずはいつものようにサンプルプロジェクトを作成しましょう。XcodeよりSingle View Applicationを選択し、以下の内容でプロジェクトを作成しましょう。尚、今回はサンプルですので、保存の際にCreate local git repository for this projectはチェックを外しておきましょう。
項目 | 設定値 |
---|---|
Product Name | SVSegmentedControlSample |
Organization Name | 自分の名前(サンプルなのでテキトー) |
Company Identifier | 会社名(サンプルなのでテキトー) |
Class Prefix | なし |
Devices | iPhone |
Use Storyboards | チェックする(ストーリーボードを使用) |
Use Automatic Reference Counting | チェックする(ARC有効) |
Include Unit Tests | チェックしない(unit testのターゲットを含まない) |
インポート
プロジェクトナビゲータにあるプロジェクトを右クリックし、「Add Files to "SVSegmentedControlSample"...」をクリックして、先ほどダウンロードしてできたディレクトリの中にSVSegmentedControlディレクトリがあるので、そのディレクトリを選択してインポートします。インポート後は以下のようになります。
ちなみに、SVSegmentedControlはARCに対応しているので、ARCを無効にする場合はSVSegmentedControl.mとSVSegmentedThumb.mに-fobjc-arcを指定してださい。
QuartzCore.frameworkの追加
SVSegmentedControlではQuartzCore.frameworkを使用するので追加しておきましょう。
サンプルソース
ViewController.mを以下のように修正してください。
ViewController.m
#import "ViewController.h" #import "SVSegmentedControl.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 表示する項目の配列を指定してSVSegmentedControlインスタンス生成 SVSegmentedControl *navSC = [[SVSegmentedControl alloc] initWithSectionTitles:@[@"First", @"Second", @"Third"]]; // 値変更時のイベントハンドラをBlocksで指定する navSC.changeHandler = ^(NSUInteger newIndex) { NSLog(@"[%@]が選択されました。", navSC.sectionTitles[newIndex]); }; // ビューに追加 [self.view addSubview:navSC]; // ビューの真ん中に表示 navSC.center = self.view.center; } @end
ViewController.mを修正したら、早速Runしてみましょう。
実行例
導入は簡単ですね。
SVSegmentedControlの構成
カスタマイズ方法を説明する前に、SVSegmentedControlの構成を理解しましょう。
SVSegmentedControlのパーツを簡単に説明します。
上の図の通りSVSegmentedControlは、
パーツ | 説明 | 関連ファイル |
---|---|---|
SVSegmentedControl | 本体 |
|
SVSegmentedThumb | 選択中を表す部品 |
|
と、選択中を表す部品が別に定義されています。これにより詳細なデザインの調整が可能となっています。
SVSegmentedControlのカスタマイズ
指定できるプロパティ
SVSegmentedControlは、SVSegmentedControlとSVSegmentedThumbを分けて設定できます。まずは本体であるSVSegmentedControlのプロパティを見てみましょう。
プロパティ | 型 | 説明 | デフォルト値 |
---|---|---|---|
sectionTitles | NSArray | 設定したセクションラベルを配列で参照できます。readonlyではないので動的に変更できそうですが、インスタンス生成後にセクション数を増減することはできないようです。 | |
sectionImages | NSArray | セクションラベルの左側に表示する画像を設定します。画像は配列で指定し、同じインデックスのセクションラベルの横に表示されます。画像はUIBarButtonのときと同様、画像のアルファチャネルを利用して表示されます。 | |
selectedIndex | NSUInteger | 現在選択中のラベルのインデックスを取得/設定します。 | 0 |
crossFadeLabelsOnDrag | BOOL | SVSegmentedThumbが選択やドラッグにより移動するときに、ラベルをクロスフェードするかどうかを設定します。 | NO |
mustSlideToChange | BOOL | このプロパティにYESを設定すると、スライド操作以外受け付けなくなります。タップでむやみに変更させたくない場合は便利ですね。 | NO |
minimumOverlapToChange | CGFloat | このプロパティは、mustSlideToChangeがYESのときに有効で、スライド操作の厳密性を定義できます。この値が1に近いほど、SVSegmentedThumbを選択したい箇所にぴったり合わせないと選択状態になりません。 | 0.66 |
touchTargetMargins | UIEdgeInsets | タッチの判定領域を縮小・拡大します。 | UIEdgeInsetsMake(0, 0, 0, 0) |
tintColor | UIColor | 背景のティントカラーを変更します。 | [UIColor grayColor] |
backgroundImage | UIImage | 背景に表示する画像を指定します。 | |
height | CGFloat | 全体の高さを指定します。 | 32.0 |
thumbEdgeInset | UIEdgeInsets | SVSegmentedThumbのマージンを指定します。 | UIEdgeInsetsMake(2, 2, 3, 2) |
titleEdgeInsets | UIEdgeInsets | セクションのパディングを指定します。 | UIEdgeInsetsMake(0, 10, 0, 10) |
cornerRadius | CGFloat | 角丸の半径を指定します。 | 4.0 |
font | UIFont | フォントを指定します。 | [UIFont boldSystemFontOfSize:15] |
textColor | UIColor | テキストの色を指定します。 | [UIColor grayColor] |
textShadowColor | UIColor | テキストの影の色を指定します。 | [UIColor blackColor] |
textShadowOffset | CGSize | テキストの影のオフセットを指定します。 | CGSizeMake(0, -1) |
次に選択状態を表すSVSegmentedThumbのプロパティを見てみましょう。
プロパティ | 型 | 説明 | デフォルト値 |
---|---|---|---|
backgroundImage | UIImage | SVSegmentedThumbの背景を指定します。 | |
highlightedBackgroundImage | UIImage | SVSegmentedThumbのハイライト時の背景を指定します。 | |
tintColor | UIColor | ティントカラーを指定します。 | [UIColor grayColor] |
textColor | UIColor | テキストの色を指定します。 | [UIColor whiteColor] |
textShadowColor | UIColor | テキストの影の色を指定します。 | [UIColor blackColor] |
textShadowOffset | CGSize | テキストの影のオフセットを指定します。 | CGSizeMake(0, -1) |
shouldCastShadow | BOOL | SVSegmentedThumbのドロップシャドウの有無を指定します。 | YES |
イベントハンドラの指定方法
SVSegmentedControlでは次の2つの方法でイベントハンドラを指定できます。
Blocksによる指定
Blocksでイベントハンドラを指定する場合は、changeHandlerプロパティに以下のように定義するだけです。
segmentedControl.changeHandler = ^(NSUInteger newIndex) { // respond to index change };
従来の方法での指定
おなじみの- addTarget:action:forControlEvents:メソッドで指定することもできます。
// Some method. { [mySegmentedControl addTarget:self action:@selector(segmentedControlChangedValue:) forControlEvents:UIControlEventValueChanged]; } - (void)segmentedControlChangedValue:(SVSegmentedControl*)segmentedControl { NSLog(@"segmentedControl did select index %i", segmentedControl.selectedIndex); }
UISwitch、UISegmentedControlと異なるのは、- addTarget:action:forControlEvents:メソッドでイベントハンドラを指定した場合、選択中の値をもう一度選択したときもハンドリングしてくれることです。(これが割と便利!)
まとめ
UISwitchやUISegmentedControlを使ってて不便だなぁと感じていた方は是非一度試してみてください!